package com.xlh.service.courseTest.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.xlh.dao.courseTest.CourseQuestionRepositoryMapper;
import com.xlh.dao.courseTest.CourseQuestionRepositoryMapperExt;
import com.xlh.dao.courseTest.helper.CourseQuestionRepositoryMapperHelper;
import com.xlh.jdbc.dao.RepositoryTemplateDAO;
import com.xlh.dto.course.CourseBasicDTO;
import com.xlh.dto.courseTest.QuestionListDTO;
import com.xlh.dto.courseTest.model.ModelNotChapterDTO;
import com.xlh.enums.FileTypeEnum;
import com.xlh.enums.courseTest.QuestionBusinessTypeEnum;
import com.xlh.enums.courseTest.QuestionTypeEnum;
import com.xlh.pojo.course.Course;
import com.xlh.pojo.courseTest.CourseQuestionRepository;
import com.xlh.pojo.courseTest.CourseQuestionRepositoryDetails;
import com.xlh.pojo.courseTest.CourseQuestionRepositoryExample;
import com.xlh.service.course.CourseService;
import com.xlh.service.courseTest.QuestionRepositoryDetailsService;
import com.xlh.service.courseTest.QuestionRepositoryService;
import com.xlh.util.BeanUtil;
import com.xlh.virtualization.constant.ContextTypeEnum;
import com.xlh.virtualization.service.ImageAllocationService;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;

import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author zhr 2019/2/12
 */
@Service
public class QuestionRepositoryServiceImpl implements QuestionRepositoryService {
    @Autowired
    private QuestionRepositoryDetailsService detailsService;
    @Autowired
    private ImageAllocationService imageAllocationService;
    @Autowired
    private CourseService courseService;

    @Autowired
    private CourseQuestionRepositoryMapper mapper;
    @Autowired
    private CourseQuestionRepositoryMapperHelper courseQuestionRepositoryMapperHelper;
    @Autowired
    private CourseQuestionRepositoryMapperExt mapperExt;
    @Autowired
    private RepositoryTemplateDAO repositoryTemplateDAO;

    /**
     * 查询用户的题库信息
     *
     * @param courseId     课程id
     * @param userId       登录用户id
     * @param businessType 题库类型
     */
    private List<CourseQuestionRepository> selectByCourseIdUserIdBusinessTypeWithoutBLOBs(Long courseId, Long userId, Integer businessType) {
        CourseQuestionRepositoryExample example = new CourseQuestionRepositoryExample();
        example.createCriteria().andUserIdEqualTo(userId).andCourseIdEqualTo(courseId)
                .andBusinessTypeEqualTo(businessType).andDelMarkEqualTo(false);
        return mapper.selectByExample(example);
    }

    @Override
    public List<ModelNotChapterDTO> questionCount(Long courseId, Long chapterId) {
        Course course = courseService.getCourseById(courseId);
        Long userId = course.getUserId();
        List<CourseQuestionRepository> questionList = selectByCourseIdUserIdBusinessTypeWithoutBLOBs(courseId, userId, QuestionBusinessTypeEnum.TEST.getCode());
        return getQuestionCount(questionList, chapterId);
    }

    @Override
    public List<CourseQuestionRepository> selectQuestionByIds(List<Long> questionIds) {
        CourseQuestionRepositoryExample example = new CourseQuestionRepositoryExample();
        example.setOrderByClause("QUESTION_TYPE ASC");
        example.createCriteria().andIdIn(questionIds).andDelMarkEqualTo(false);
        return mapper.selectByExampleWithBLOBs(example);
    }

    @Override
    public List<CourseQuestionRepository> selectQuestionIdByChapterId(Long chapterId, QuestionBusinessTypeEnum businessTypeEnum) {
        CourseQuestionRepositoryExample example = new CourseQuestionRepositoryExample();
        example.setOrderByClause("QUESTION_TYPE ASC");
        example.createCriteria().andChapterIdEqualTo(chapterId).andBusinessTypeEqualTo(businessTypeEnum.getCode())
                .andDelMarkEqualTo(false);
        return mapper.selectByExampleWithBLOBs(example);
    }

    @Override
    public CourseQuestionRepository selectByPrimaryKey(Long id) {
        return mapper.selectByPrimaryKey(id);
    }

    @Override
    public Long getCourseId(Long id) {
        CourseQuestionRepository repository = selectByPrimaryKeyWithoutBLOBs(id);
        return repository == null ? null : repository.getCourseId();
    }

    private CourseQuestionRepository selectByPrimaryKeyWithoutBLOBs(Long id) {
        CourseQuestionRepositoryExample example = new CourseQuestionRepositoryExample();
        example.createCriteria().andIdEqualTo(id).andDelMarkEqualTo(false);
        List<CourseQuestionRepository> resultList = mapper.selectByExample(example);
        return CollectionUtils.isEmpty(resultList) ? null : resultList.get(0);
    }

    @Override
    public void deleteQuestion(List<Long> chapterIds) {
        // 删除题目
        deleteQuestionByCourseIdChapterId(chapterIds, null);
        // 回收答案脏数据
        detailsService.cleanData();
    }

    @Override
    public void deleteQuestion(List<Long> chapterIds, QuestionBusinessTypeEnum typeEnum) {
        // 删除题目
        deleteQuestionByCourseIdChapterId(chapterIds, typeEnum);
        // 回收答案脏数据
        detailsService.cleanData();
    }

    @Override
    public void moveQuestionToSpecifyUser(List<Long> chapterIds, Long userId) {

        if(CollectionUtil.isEmpty(chapterIds)
                || ObjectUtil.isNull(userId)) {
            return;
        }
        CourseQuestionRepositoryExample example = new CourseQuestionRepositoryExample();
        example.createCriteria().andChapterIdIn(chapterIds).andDelMarkEqualTo(false);

        CourseQuestionRepository record = new CourseQuestionRepository();
        record.setUserId(userId);
        mapper.updateByExampleSelective( record, example );

    }

    /**
     * 按照根据课程id或章节id删除题目
     */
    private void deleteQuestionByCourseIdChapterId(List<Long> chapterIds, QuestionBusinessTypeEnum typeEnum) {
        CourseQuestionRepositoryExample example = new CourseQuestionRepositoryExample();
        CourseQuestionRepositoryExample.Criteria criteria = example.createCriteria();
        if (typeEnum != null) {
            criteria.andBusinessTypeEqualTo(typeEnum.getCode());
        }
        if (CollectionUtils.isNotEmpty(chapterIds)) {
            criteria.andChapterIdIn(chapterIds);
        }
        if (criteria.isValid()) {
            mapper.deleteByExample(example);
        }
    }

    private List<ModelNotChapterDTO> getQuestionCount(List<CourseQuestionRepository> questionList, Long chapterId) {
        List<ModelNotChapterDTO> resultList = Lists.newArrayList();

        if (chapterId != null) {
            Map<Long, List<CourseQuestionRepository>> questionListChapterMap =
                    BeanUtil.aggByKeyToList("chapterId", questionList);
            questionList = questionListChapterMap.get(chapterId);
        }

        Map<Integer, List<CourseQuestionRepository>> questionListTypeMap =
                BeanUtil.aggByKeyToList("questionType", questionList);
        questionListTypeMap.forEach((type, list) -> {
            ModelNotChapterDTO dto = new ModelNotChapterDTO(type, null, list.size(), null);
            resultList.add(dto);
        });

        return resultList;
    }

    @Override
    public List<QuestionListDTO> questionList(
            String keyWord, Long courseId, Long chapterId, Integer questionType,
            Integer businessType, Long userId, Boolean isPreset
    ) {
        return mapperExt.questionList(keyWord, courseId, chapterId, questionType, businessType, userId, isPreset);
    }

    @Override
    public List<QuestionListDTO> questionListOther(String keyWord, Long courseId, Long chapterId, Integer questionType, Integer businessType, Long userId, Boolean isPreset) {
        return mapperExt.questionListOther(keyWord, courseId, chapterId, questionType, businessType, userId, isPreset);
    }

    @Override
    public List<CourseQuestionRepository> getUserQuestionList(Long courseId, Long userId, Integer businessType) {
        CourseQuestionRepositoryExample example = new CourseQuestionRepositoryExample();
        example.createCriteria().andCourseIdEqualTo(courseId).andUserIdEqualTo(userId).andBusinessTypeEqualTo(businessType).andDelMarkEqualTo(false);

        List<CourseQuestionRepository> list = mapperExt.selectByExample(example);
        return CollectionUtils.isEmpty(list) ? Lists.newArrayList() : list;
    }


    /**
     * 将指定的题目列表插入至数据库
     *
     * @param courseId       课程id
     * @param userId         登录用户id
     * @param questionList   题目列表
     * @param detailsListMap <题目id，答案列表>映射集
     */
    @Override
    public void importQuestion(
            Long courseId, Long userId, Boolean isTeacher, Boolean isPresetCourse,
            List<CourseQuestionRepository> questionList,
            Map<Long, List<CourseQuestionRepositoryDetails>> detailsListMap
    ) {
        int listSize = questionList.size();

        List<CourseQuestionRepository> copyList = Lists.newArrayList();
        // 重设题干中的部分字段
        for (CourseQuestionRepository repository : questionList) {
            CourseQuestionRepository copy = BeanUtil.transform(CourseQuestionRepository.class, repository);

            if (copy == null) {
                copy = new CourseQuestionRepository();
            }

            if (!isTeacher || isPresetCourse) {
                copy.setSourceQuestionId(repository.getId());
            }
            copy.setId(null);
            copy.setCourseId(courseId);
            copy.setIsPreset(!isTeacher && isPresetCourse);
            copy.setUserId(userId);

            copyList.add(copy);
        }

        // 批量插入题干
        insertBatch(copyList);

        // 重设答案选项的映射题目id
        List<CourseQuestionRepositoryDetails> detailsList = Lists.newArrayList();
        for (int i = 0; i < listSize; i++) {
            CourseQuestionRepository repository = questionList.get(i);
            CourseQuestionRepository copy = copyList.get(i);

            // 拷贝镜像分配
            if (QuestionTypeEnum.isExperiment(repository.getQuestionType())) {
                imageAllocationService.copyImageAllocation(ContextTypeEnum.QUESTION.getCode(), repository.getId(), copy.getId());
            }

            // 修改详情对应的题目id，回填答案主键id，并放入到detailsList中
            List<CourseQuestionRepositoryDetails> courseQuestionRepositoryDetailsList = detailsListMap.get(repository.getId());
            if (CollectionUtils.isNotEmpty(courseQuestionRepositoryDetailsList)) {
                for (CourseQuestionRepositoryDetails details : courseQuestionRepositoryDetailsList) {
                    details.setQuestionId(copy.getId());
                }
                detailsList.addAll(courseQuestionRepositoryDetailsList);
            }
        }

        // 批量插入答案
        detailsService.insertBatch(detailsList);
    }

    @Override
    public void copyRepository(Long courseId, Long chapterId, Long newChapterId, Long newCourseId, Long userId, Boolean isTeacher) {
        CourseBasicDTO course = courseService.getCourse(courseId);
        Boolean isPresetCourse = course.getPreseted();

        List<CourseQuestionRepository> questionList = selectByCourseIdChapterId(courseId, chapterId);
        if (CollectionUtils.isEmpty(questionList)) {
            return;
        }
        questionList.forEach(question -> question.setChapterId(newChapterId));

        List<Long> questionIdList = questionList.stream().map(CourseQuestionRepository::getId).collect(Collectors.toList());
        // 查询所有的预制答案
        Map<Long, List<CourseQuestionRepositoryDetails>> presetDetailsListMap = detailsService.getDetailsMap(questionIdList, FileTypeEnum.MARKDOWN);

        // 为了减少mapper的反复调用，使用mybatis批处理，需要手动添加题目id
        // 获取主表中当前id的最大值
        importQuestion(newCourseId, userId, isTeacher, isPresetCourse, questionList, presetDetailsListMap);
    }

    private List<CourseQuestionRepository> selectByCourseIdChapterId(Long courseId, Long chapterId) {
        CourseQuestionRepositoryExample example = new CourseQuestionRepositoryExample();
        CourseQuestionRepositoryExample.Criteria criteria = example.createCriteria().andDelMarkEqualTo(false);
        if (chapterId != null) {
            criteria.andChapterIdEqualTo(chapterId);
        } else {
            criteria.andChapterIdIsNull();
        }
        if (courseId != null) {
            criteria.andCourseIdEqualTo(courseId);
        }
        return mapper.selectByExampleWithBLOBs(example);
    }


    @Override
    public Map<Long, Boolean> getExistMap(List<Long> chapterIds) {
        Map<Long, Boolean> result = Maps.newHashMap();
        List<CourseQuestionRepository> questionList = selectByChapterIdsWithoutBlob(chapterIds, QuestionBusinessTypeEnum.PRACTICE);
        Map<Long, List<CourseQuestionRepository>> chapterIdQuestionListMap = BeanUtil.aggByKeyToList("chapterId", questionList);
        chapterIds.forEach(chapterId -> result.put(chapterId, CollectionUtils.isNotEmpty(chapterIdQuestionListMap.get(chapterId))));
        return result;
    }

    @Override
    public long countByExample(CourseQuestionRepositoryExample example) {
        return mapper.countByExample(example);
    }

    @Override
    public void insertSelective(CourseQuestionRepository repository) {
        mapper.insertSelective(repository);
    }

    @Override
    public List<CourseQuestionRepository> selectByExample(CourseQuestionRepositoryExample example) {
        List<CourseQuestionRepository> list = mapper.selectByExample(example);
        return CollectionUtils.isEmpty(list) ? Lists.newArrayList() : list;
    }

    @Override
    public Long selectMaxId() {
        return mapperExt.selectMaxId();
    }

    @Override
    public void insertBatch(List<CourseQuestionRepository> questionList) {
        if (CollectionUtils.isNotEmpty(questionList)) {
            mapperExt.insertBatch(questionList);
        }
    }

    @Override
    public void updateByPrimaryKeySelective(CourseQuestionRepository question) {
        mapper.updateByPrimaryKeySelective(question);
    }

    @Override
    public void updateDeleteByIds(List<Long> questionIds) {
        // 设置where条件
        CourseQuestionRepositoryExample example = new CourseQuestionRepositoryExample();
        example.createCriteria().andIdIn(questionIds);

        // 设置删除状态
        CourseQuestionRepository updateDelMarkModel = new CourseQuestionRepository();
        updateDelMarkModel.setDelMark(true);

        // 执行删除操作
        mapper.updateByExampleSelective(updateDelMarkModel, example);
    }

    @Override
    public List<QuestionListDTO> questionListByIds(List<Long> ids) {
        return mapperExt.questionListByIds(ids);
    }

    @Override
    public void copyRepositoryOverServer(JdbcTemplate jdbcTemplate, Map<Long, Long> courseIdMap, Map<Long, Long> chapterIdMap) {
        // 获取待导入的题库数据
        List<CourseQuestionRepository> questionList = Lists.newArrayList();
        questionList.addAll(repositoryTemplateDAO.selectByChapterIds(jdbcTemplate, Lists.newArrayList(chapterIdMap.keySet())));
        questionList.addAll(repositoryTemplateDAO.selectNoChapterId(jdbcTemplate, Lists.newArrayList(courseIdMap.keySet())));
        // 题目排序
        questionList.sort(Comparator.comparing(CourseQuestionRepository::getId));

        List<Long> questionIdList = questionList.stream().map(CourseQuestionRepository::getId).collect(Collectors.toList());
        // 获取待导入的答案选项数据
        List<CourseQuestionRepositoryDetails> detailsList = repositoryTemplateDAO.selectDetails(jdbcTemplate, questionIdList);

        // 处理题库数据信息
        questionList.forEach(question -> {
            question.setId(null);
            question.setCreateTime(null);
            question.setUpdateTime(null);
            question.setCourseId(courseIdMap.get(question.getCourseId()));
            question.setSourceQuestionId(null);
            if (question.getChapterId() != null) {
                question.setChapterId(chapterIdMap.get(question.getChapterId()));
            }
        });
        // 执行批量插入操作
        mapperExt.insertBatch(questionList);

        List<Long> questionIdListNew = questionList.stream().map(CourseQuestionRepository::getId).collect(Collectors.toList());

        // 将题目id转为映射
        Map<Long, Long> questionIdMap = convertIdListToMap(questionIdList, questionIdListNew);

        // 处理答案选项数据信息
        detailsList.forEach(details -> {
            details.setId(null);
            details.setCreateTime(null);
            details.setUpdateTime(null);
            details.setQuestionId(questionIdMap.get(details.getQuestionId()));
        });
        // 批量插入答案选项数据
        detailsService.insertBatch(detailsList);
    }

    @Override
    public List<Long> findHavePracticeChapterIds(List<Long> chapterIds) {

        if(CollectionUtil.isEmpty(chapterIds)){
            return Lists.newArrayList();
        }
        List<CourseQuestionRepository> questionByChapterIds = courseQuestionRepositoryMapperHelper.
                findQuestionByChapterIds(chapterIds, QuestionBusinessTypeEnum.PRACTICE.getCode());
        Map<Long, List<CourseQuestionRepository>> havePracticeChapterIds = questionByChapterIds.stream()
                .collect(Collectors.groupingBy(CourseQuestionRepository::getChapterId));
        return Lists.newArrayList(havePracticeChapterIds.keySet());
    }

    @Override
    public void updateByCourseId(CourseQuestionRepository courseQuestionRepository, Long courseId) {

        courseQuestionRepositoryMapperHelper.updateByCourseId(courseQuestionRepository, courseId);
    }

    private Map<Long, Long> convertIdListToMap(List<Long> questionIdList, List<Long> questionIdListNew) {
        Map<Long, Long> map = Maps.newHashMap();
        int max = questionIdList.size();
        for (int i = 0; i < max; i++) {
            map.put(questionIdList.get(i), questionIdListNew.get(i));
        }

        return map;
    }

    private List<CourseQuestionRepository> selectByChapterIdsWithoutBlob(List<Long> chapterIds, QuestionBusinessTypeEnum typeEnum) {
        CourseQuestionRepositoryExample example = new CourseQuestionRepositoryExample();
        example.createCriteria().andChapterIdIn(chapterIds).andBusinessTypeEqualTo(typeEnum.getCode()).andDelMarkEqualTo(false);
        List<CourseQuestionRepository> result = mapper.selectByExample(example);
        return CollectionUtils.isEmpty(result) ? Lists.newArrayList() : result;
    }

    private List<CourseQuestionRepository> selectByCourseIdChapterIdUserIdBusinessType(
            Long courseId, Long chapterId, QuestionBusinessTypeEnum businessType
    ) {
        CourseQuestionRepositoryExample example = new CourseQuestionRepositoryExample();
        CourseQuestionRepositoryExample.Criteria criteria = example.createCriteria()
                .andBusinessTypeEqualTo(businessType.getCode()).andDelMarkEqualTo(false);
        if (chapterId != null) {
            criteria.andChapterIdEqualTo(chapterId);
        }
        if (courseId != null) {
            criteria.andCourseIdEqualTo(courseId);
        }
        return mapper.selectByExampleWithBLOBs(example);
    }
}
